package thread;

import java.util.ArrayList;
import java.util.List;

/**
 * synchronized是java的关键字，可以用在方法或这代码块中。
 *  用在方法中：
 *      1：如果是静态方法，则默认的【锁对象是当前类的class对象】。
 *      2：如果是非静态方法，则默认的【锁对象是this对象】。
 * 用在代码块中：
 *      都需要显示的指示【锁对象】。不过有一点需要注意，静态代码块中，不能使用非静态的对象（保证java的语义正确）。
 */
public class SynchronizedTest {
    /**
     * 1：用在方法上。
     *  用在非静态方法上，等价于锁【this（当前）】对象。
     */
    public synchronized void test1(){
        System.out.println("...");
    }

    /**
     * 2：用在静态方法上：等价于锁【this.class（当前类的类对象）】对象。
     *  比如：【SynchronizedTest.class】
     */
    private synchronized static void test2(){
        System.out.println("222");
    }

    /**
     * 3：用在代码块中，无论是静态还是非静态的代码块，都需要用户指定锁的对象。
     */
    private void test3(){
        synchronized (this){
            System.out.println("333");
        }
    }

    /**
     * 4：静态代码块中。
     */
    static {
        synchronized (SynchronizedTest.class) {
            System.out.println("444");
        }
    }

    /**
     * 5：非静态代码块中。
     */
    {
        synchronized (this){
            System.out.println("555");
        }
    }

    /**
     * 局部变量的线程安全问题：
     *  如下所示：访问局部变量，会出现线程安全问题。
     *  实际上这种简单的操作，idea可以识别出来（比如int），但是对于一些复杂的集合操作（比如list.remove），idea就很难识别出来了。
     *      这就是局部变量，【他自己将引用暴露给了，某个方法】。【某个方法又暴露给了新的线程】。【所以这就是局部变量出现的引用暴露】。
     *      【所以，我们需要使用private、final等修饰符，禁止子类重写该方法，防止局部变量的引用暴露】。
     */
    private void local(){
        ArrayList<String> i = new ArrayList<>();
        Thread t1 = thread1(i,"t1");
        Thread t2 = thread1(i,"t2");
        t1.start();
        t2.start();
    }

    private Thread thread1(ArrayList<String> i, String t1) {
        Thread thread = new Thread(t1){
            @Override
            public void run() {
                i.remove("1");
            }
        };
        return thread;
    }

}

